from fastapi import HTTPException
from config import Config
from utils import (
    convert_params, 
    service, 
    process_analysis_and_chart, 
    call_etc_service_common,
    get_user_merchants, 
    safe_extract_merchant_name,
    extract_merchant_keyword_from_history
)
from models import ETCInvoiceParams
from chat_history import chat_history_manager
import logging
import time
from typing import Optional
from utils import analyze_data, TrendAnalyzer, should_include_analysis, should_include_chart

# 处理ETC发票数据
async def process_etc_invoice_data(user_query: str, phone_number: str, conversation_id: str, include_analysis: Optional[bool] = None, include_chart: Optional[bool] = None, timeout: int = 60, params: Optional[dict] = None) -> dict:
    start_time = time.time()
    logging.info(f"[步骤5-ETC发票数据处理] 开始处理ETC发票数据")
    
    # 获取对话历史
    history = chat_history_manager.get_history(conversation_id)
    logging.info(f"[对话管理] 获取到历史消息数量: {len(history)}")
    
    # 如果外部传入了params参数，检查是否包含必要参数；如果不包含或未传入，则自动提取参数
    if params is None or not all(key in params for key in ["userId", "kpMerid", "kpMonth"]):
        # 转换用户查询为API参数，并传递历史对话数据
        auto_params = await convert_params(user_query, "etc_invoice", phone_number, history)
        logging.info(f"[参数转换] ETC发票查询参数自动提取: {auto_params}")
        
        # 检查是否为模糊关键词处理结果
        if isinstance(auto_params, dict) and auto_params.get('is_ambiguous_keyword'):
            # 如果是模糊关键词，直接返回反问消息
            logging.info(f"[参数转换] 检测到模糊关键词，返回反问消息")
            ambiguous_response = auto_params.get('ambiguous_response', {})
            
            # 保存对话记录到本地对话ID中
            chat_history_manager.add_message(conversation_id, "user", user_query)
            chat_history_manager.add_message(conversation_id, "assistant", ambiguous_response.get('response_message', ''))
            
            # 构建与普通查询结果一致的返回格式
            result = {
                "user_query": user_query,
                "summary": ambiguous_response.get('response_message', ''),
                "records": [],
                "download_links": [],
                "extend_question": ""
            }
            
            return {
                "answer": ambiguous_response.get('response_message', ''),
                "conversation_id": conversation_id,
                "result": result
            }
        
        # 如果外部传入了params，则合并自动提取的参数
        if params is not None:
            # 保留外部传入的参数，但用自动提取的参数补充缺失的必要参数
            for key in ["userId", "kpMerid", "kpMonth"]:
                if key not in params or not params[key]:
                    params[key] = auto_params[key]
            
            # 如果历史对话中包含商户信息，尝试从历史中提取商户ID
            if history and not params.get("kpMerid"):
                try:
                    # 从历史对话中提取商户关键词
                    merchant_keyword = await extract_merchant_keyword_from_history(history, phone_number)
                    if merchant_keyword:
                        # 获取用户可查询商户列表
                        available_merchants = await get_user_merchants(phone_number, return_empty_on_error=True)
                        # 匹配商户ID
                        for merchant in available_merchants:
                            if isinstance(merchant, dict) and merchant.get('merName') == merchant_keyword:
                                params["kpMerid"] = [merchant.get('merId')]
                                logging.info(f"[参数转换] 从历史对话中提取到商户ID: {params['kpMerid']}")
                                break
                except Exception as e:
                    logging.error(f"[参数转换] 从历史对话中提取商户ID失败: {str(e)}")
            
            logging.info(f"[参数转换] ETC发票查询参数合并外部和自动提取: {params}")
        else:
            params = auto_params
    else:
        logging.info(f"[参数转换] ETC发票查询参数使用外部传入: {params}")
    
    # 提取参数并验证
    try:
        # 检查kpMerid是否为空列表
        kp_mer_id = params.get("kpMerid", [])
        if isinstance(kp_mer_id, list) and len(kp_mer_id) == 0:
            logging.warning(f"[参数验证] ETC发票参数验证失败: kpMerid为空列表")
            raise HTTPException(status_code=400, detail="请指定要查询的商户，不能查询全量数据")
        
        validated_params = ETCInvoiceParams(
            userId=params.get("userId", ""),
            kpMerid=kp_mer_id,
            kpMonth=params.get("kpMonth", ""),
            start=params.get("start", 0),
            limit=params.get("limit", 10),
            kpStat=params.get("kpStat"),
            kpType=params.get("kpType")
        )
        logging.info(f"[参数验证] ETC发票参数验证通过: {validated_params.model_dump()}")
    except HTTPException:
        # 重新抛出HTTPException
        raise
    except Exception as e:
        logging.error(f"[参数验证] ETC发票参数验证失败: {str(e)}")
        raise HTTPException(status_code=400, detail=f"参数验证失败：{str(e)}")
    
    # 调用ETC发票API
    try:
        data = await service.call_api(Config.ETC_INVOICE_API_PATH, params, base_url=Config.ETC_INVOICE_API_BASE_URL)
    except Exception as e:
        logging.error(f"[API调用] ETC发票API调用失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"API调用失败：{str(e)}")
    
    # 确保data是字典类型
    if not isinstance(data, dict):
        logging.error(f"[API调用] ETC发票API返回类型错误，期望字典但得到: {type(data)}")
        raise HTTPException(status_code=500, detail="API返回数据格式错误")
    
    logging.info(f"[API调用] ETC发票数据获取成功: {len(data.get('respData', []))}条记录")
    
    # 检查API调用是否成功
    if data.get('code') not in ['10000', '0000']:
        error_msg = data.get('msg', '未知错误')
        logging.error(f"[API错误] ETC发票查询失败: {error_msg}")
        # 如果错误消息中包含"查询成功"字样，则使用更准确的错误描述
        if "查询成功" in error_msg:
            error_msg = "API返回状态异常，请稍后重试"
        raise HTTPException(status_code=400, detail=f"查询失败：{error_msg}")

    # 根据API返回的数据结构获取发票列表
    invoice_list = data.get('respData', []) or data.get('etcMerInvoiceDtlList', [])
    
    # 确保invoice_list是列表类型
    if not isinstance(invoice_list, list):
        logging.error(f"[数据处理] ETC发票数据格式错误，期望列表但得到: {type(invoice_list)}")
        invoice_list = []
    
    total_count = data.get('total', len(invoice_list))
    logging.info(f"[数据处理] ETC发票记录数量: {total_count}条")

    # 直接使用API返回的kpMerName作为商户名称，不再需要从商户列表中查找
    # 如果有发票数据，从第一条记录中获取商户名称；否则使用"未知"
    if invoice_list and isinstance(invoice_list[0], dict):
        merchant_name = invoice_list[0].get('kpMerName', '未知')
        logging.info(f"[商户名称获取] 直接从发票数据中获取商户名称: {merchant_name}")
    else:
        merchant_name = "未知"
        logging.info(f"[商户名称获取] 无发票数据，使用默认商户名称: {merchant_name}")

    # 确定是否进行分析和画图
    do_analysis = include_analysis if include_analysis is not None else should_include_analysis(user_query, "etc_invoice")
    do_chart = include_chart if include_chart is not None else should_include_chart(user_query, "etc_invoice")
    
    # 构建竖向Markdown表格格式的结果
    if total_count == 0:
        # 尝试扩展查询
        try:
            from utils_1 import enhance_no_data_response
            # 构建原始响应对象
            original_response = {
                "user_query": user_query,
                "summary": "### 未找到符合条件的ETC发票记录",
                "records": [],
                "download_links": []
            }
            
            # 调用扩展查询功能
            enhanced_response = await enhance_no_data_response(
                response=original_response,
                params=params,
                api_path=Config.ETC_INVOICE_API_PATH,
                query_type="etc_invoice",
                service=call_etc_invoice_service,
                user_query=user_query
            )
            
            # 如果扩展查询有结果，返回扩展后的响应
            if enhanced_response:
                return enhanced_response
            
            # 如果扩展查询也没有结果，使用原始响应
            result_lines = [f"### 未找到符合条件的ETC发票记录"]
            
        except Exception as e:
            logging.error(f"[扩展查询] ETC发票扩展查询失败: {str(e)}")
            result_lines = [f"### 未找到符合条件的ETC发票记录"]
    else:
        result_lines = [f"### 查询成功，共找到{total_count}条ETC发票记录"]
    
    # 如果用户要求数据分析，则显示数据分析模式的提示信息
    if do_analysis or do_chart:
        result_lines = [f"### 数据分析结果"]
    
    # 创建独立的记录数组
    records = []
    download_links = []
    for idx, invoice in enumerate(invoice_list, 1):
        # 确保invoice是字典类型
        if not isinstance(invoice, dict):
            logging.warning(f"[数据处理] 跳过非字典类型的发票数据: {invoice}")
            continue
            
        # 提取当前发票的PDF链接
        pdf_url = invoice.get('pdfUrl')
        
        # 将http链接转换为https链接，转换所有链接
        if pdf_url and pdf_url.startswith('http://'):
            pdf_url = pdf_url.replace('http://', 'https://', 1)
            logging.info(f"[链接转换] 已将HTTP链接转换为HTTPS: {pdf_url}")
        
        # 将下载链接添加到列表
        download_links.append({
            'index': idx,
            'download_url': pdf_url,
            'file_type': 'pdf'
        })
        
        # 构建单条记录的完整内容
        record_content = []
        record_content.append(f"#### 第{idx}条ETC发票记录")
        record_content.append(f"| 序号 | {idx} |")
        record_content.append("|------|-----|")
        record_content.append(f"| 商户名称 | {invoice.get('kpMerName', '未知')} |")
        record_content.append(f"| 开票月份 | {invoice.get('kpMonth', '未知')} |")
        record_content.append(f"| 价税合计(元) | {float(invoice.get('jshj', 0))/100:.2f} |")
        record_content.append(f"| 发票类型 | {invoice.get('kpTypeDesc', '未知')} |")
        
        # 将完整记录内容作为单个字符串添加到records数组
        records.append("\n".join(record_content))

    # 使用公共函数处理数据分析和趋势图生成
    analysis_result = await process_analysis_and_chart(
        data=data,
        data_list=invoice_list,
        user_query=user_query,
        analysis_type="etc_invoice",
        include_analysis=include_analysis,
        include_chart=include_chart,
        date_field='endDate',
        value_field='jshj',
        title=f'{merchant_name}ETC发票金额趋势分析',
        x_label='月份',
        y_label='金额(元)',
        value_converter=lambda x: float(x)/100  # 将分转换为元
    )
    
    trend_data = analysis_result["trend_data"]
    text_analysis = analysis_result["text_analysis"]
    
    # 添加调试日志
    logging.info(f"[ETC发票] include_analysis参数值: {include_analysis}")
    logging.info(f"[ETC发票] include_chart参数值: {include_chart}")
    logging.info(f"[ETC发票] text_analysis是否存在: {bool(text_analysis)}")
    logging.info(f"[ETC发票] trend_data是否存在: {bool(trend_data)}")
    
    logging.info(f"[ETC发票] 最终do_analysis值: {do_analysis}")
    logging.info(f"[ETC发票] 最终do_chart值: {do_chart}")

    # 使用传入的conversation_id
    logging.info(f"[对话管理] 使用传入的conversation_id: {conversation_id}")

    # 构建响应对象
    response = {
        "user_query": user_query,
        "summary": result_lines[0] if result_lines else ("数据分析结果" if do_analysis or do_chart else ""),
        "records": records if not (do_analysis or do_chart) else [],  # 分开问时只返回查询数据
        "download_links": download_links if not (do_analysis or do_chart) else []  # 分开问时只返回下载链接
    }
    
    # 仅在用户没有要求分析或画图时返回趋势分析字段
    if not do_analysis and not do_chart:
        response["extend_question"] = "对数据进行趋势分析和可视化"
    
    # 只有在生成了分析结果时才包含analysis字段
    if text_analysis:
        response["analysis"] = text_analysis
        logging.info(f"[ETC发票] 添加analysis字段，内容: {response['analysis']}")
    
    # 只有在生成了趋势图时才包含chart字段
    if trend_data and "trend_chart" in trend_data:
        response["chart"] = trend_data["trend_chart"]
    
    # 添加debug_info字段，与正常发票服务保持一致
    if params.get("debug", False):
        response["debug_info"] = {
            "generated_params": params,
            "target_api_url": f"{Config.ETC_INVOICE_API_BASE_URL}{Config.ETC_INVOICE_API_PATH}",
            "raw_response": data
        }
    
    end_time = time.time()
    logging.info(f"[步骤5-ETC发票数据处理] 处理ETC发票数据耗时: {end_time - start_time:.2f}秒")
    return response

# 封装函数，类似Dify服务
async def call_etc_invoice_service(
    user_query: str, 
    phone_number: str, 
    conversation_id: Optional[str] = None, 
    debug: bool = False, 
    include_analysis: Optional[bool] = None, 
    include_chart: Optional[bool] = None, 
    is_monitor: bool = False,
    params: Optional[dict] = None
) -> dict:
    """调用ETC发票服务的封装函数
    
    Args:
        user_query: 用户查询
        phone_number: 手机号
        conversation_id: 对话ID
        debug: 是否调试模式
        include_analysis: 是否包含分析
        include_chart: 是否包含图表
        is_monitor: 是否监控模式
        params: 外部传入的参数，如果不指定则自动提取
        
    Returns:
        查询结果
    """
    # 构建params参数
    if params is None:
        params = {}
    
    # 添加默认参数
    params.update({
        "debug": debug,
        "is_monitor": is_monitor,
        "timeout": 60
    })
    
    return await call_etc_service_common(
        user_id=phone_number,
        user_query=user_query,
        params=params,
        process_func=process_etc_invoice_data,
        conversation_id=conversation_id,
        include_analysis=include_analysis,
        include_chart=include_chart,
        service_name="ETC发票服务"
    )